﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ais3.DBS.Requirement.BE;
using Ais3.DBS.Requirement.BE.Enum.RequirementDocEnum;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Data;
using Ais3.DBS.General.BE.Enum;
using Ais3.DBS.General.BE;

namespace Ais3.DBS.Requirement.DALC
{
	class RequirementDocDA : BaseDA
	{

		private PdDocDA DataAccessForPd
		{
			get
			{
				return new PdDocDA();
			}
		}
		/// <summary>
		/// Получить Требование об уплате по Ид. Если ТУ не найдено - возникает ошибка
		/// </summary>
		/// <param name="id">Ид требования об уплате</param>
		/// <returns>Требование об уплате</returns>
		public RequirementDoc GetById(long id)
		{
			bool haveResult = false;
			RequirementDoc result = new RequirementDoc();

			OracleCommand command = new OracleCommand();
			command.CommandTimeout = GetTimeout(CommandTimeoutType.Default);
			command.CommandType = CommandType.StoredProcedure;
			command.CommandText = DbSchemaName0508 + "pac$req.p$get_by_id";
			command.Parameters.Add("vp_id", OracleDbType.Int64).Value = id;

			ExecuteReaderCommand(command, delegate(OracleDataReader dalReader)
			{
				haveResult = dalReader.Read();

				if (!haveResult)
					throw new Exception(String.Format("ТУ с ИД={0} не найдено в БД", id));

				result = GetDocHeader(dalReader);
			});

			if (haveResult)
			{
				//// Платежные документы
				//if (result.TaxpayerDbsType == TaxpayerTypeDbs.Fl)
				//    result.PdDocList = DataAccessForPd.GetByRequirementDocId(result.Id);

			//    // Данные налоговой проверки
			//    result.TaxCheck = GetTaxCheck(result.Id);

				// Недоимки Требования
				result.DocDebts = GetDocDebts(result);

			//    // Данные налоговой проверки по НДС
			//    if (result.DocType == ProcessType.ReqRefund)
			//    {
			//        result.TaxCheckNds = DataAccessForReqRefund.GetTaxcheckNds(result.Id);

			//        // Также для Требований о возврате вычисляем суммы
			//        result.RefundInitialInfo = new ReqRefundInfo();
			//        result.RefundInitialInfo.ExcessiveRefundSum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Nalog &&
			//            x.TransferDcnType == TransferDecisionType.Refund).
			//            Sum(y => y.DebtUnpaidAmount);
			//        result.RefundInitialInfo.ExcessiveCreditSum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Nalog &&
			//            x.TransferDcnType == TransferDecisionType.Credit).
			//            Sum(y => y.DebtUnpaidAmount);
			//        result.RefundInitialInfo.InterestPar1761No10Sum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Procent &&
			//            x.InterestType == InterestType.Par176_1No10).
			//            Sum(y => y.DebtUnpaidAmount);
			//        result.RefundInitialInfo.InterestPar1761No17Sum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Procent &&
			//            x.InterestType == InterestType.Par176_1No17).
			//            Sum(y => y.DebtUnpaidAmount);

			//        result.RefundCurrentInfo = new ReqRefundInfo();
			//        result.RefundCurrentInfo.ExcessiveRefundSum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Nalog &&
			//            x.TransferDcnType == TransferDecisionType.Refund).
			//            Sum(y => y.LastUnpaidAmount);
			//        result.RefundCurrentInfo.ExcessiveCreditSum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Nalog &&
			//            x.TransferDcnType == TransferDecisionType.Credit).
			//            Sum(y => y.LastUnpaidAmount);
			//        result.RefundCurrentInfo.InterestPar1761No10Sum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Procent &&
			//            x.InterestType == InterestType.Par176_1No10).
			//            Sum(y => y.LastUnpaidAmount);
			//        result.RefundCurrentInfo.InterestPar1761No17Sum = result.DocDebts.Where(x =>
			//            x.PaymentKind == PaymentKind.Procent &&
			//            x.InterestType == InterestType.Par176_1No17).
			//            Sum(y => y.LastUnpaidAmount);
			//    }

			//    // Сведения о банковской гарантии
			//    if (result.DocType == ProcessType.ReqRefund ||
			//        result.DocType == ProcessType.TaxExcise)
			//        result.BankGuaranteeInfo = DataAccessForReqRefund.GetBankGuarantee(result.Id);

			//    // Документ-основание отзыва (для проектов документов проверка на признак 
			//    // отозванного ТУ не эффективна)
			//    if (result.ResponseSign == ResponseSignType.Back ||
			//        result.DocProcessingState != DocProcessingStateType.FinaleReadyState)
			//        result.ResponseBaseDoc = DataAccessForResponseBase.GetByRequirementId(result.Id);

				// Заполняем строки ТУ
				FillRequirementDocLines(result);
			}

			return result;
		}
		/// <summary>
		/// Группирует недоимки в строки Требования об уплате
		/// </summary>
		/// <param name="reqDoc">Требование об уплате</param>
		private void FillRequirementDocLines(RequirementDoc reqDoc)
		{
			foreach (IList<RequirementDocDebt> reqLineDebts in reqDoc.DocDebts.GroupBy(
				x => new
				{
					TaxRecordId = x.Tax.RecordId,
					x.PaymentTerm,
					x.PaymentKind,
					OkatoRecordId = x.Okato.RecordId,
					//x.TaxpayerStatus.Id,
					x.TaxpayerInfo.Kpp,
					x.TaxpayerInfo.TaxOrganId,
					x.PenyaType
				}).OrderBy(x => x.Key.PaymentTerm))
			{
				reqDoc.DocLines.Add(new RequirementDocLine(reqLineDebts.ToList()));
			}
		}
		private IList<RequirementDocDebt> GetDocDebts(RequirementDoc reqDoc)
		{
			IList<RequirementDocDebt> result = new List<RequirementDocDebt>();

			OracleCommand cmd = new OracleCommand();
			cmd.CommandTimeout = GetTimeout(CommandTimeoutType.Default);
			cmd.CommandType = CommandType.StoredProcedure;
			cmd.CommandText = DbSchemaName0508 + "pac$req.p$get_debts_by_req_id";
			cmd.Parameters.Add("vp_req_id", reqDoc.Id);

			ExecuteReaderCommand(cmd, delegate(OracleDataReader dalReader)
			{
				while (dalReader.Read())
					result.Add(GetDebtHeader(dalReader));
			});

			//// Заполняем данные НП 
			//foreach (IList<RequirementDocDebt> docList in result.GroupBy(x => new
			//{
			//    x.TaxpayerInfo.TaxpayerId,
			//    x.TaxpayerInfo.TaxpayerObjId,
			//    x.TaxpayerInfo.TaxOrganId
			//}))
			//{
			//    TaxpayerInDoc taxpayerInfo = BusinessFacadeForTaxpayer.GetTaxpayerInfo(new TaxpayerPicker()
			//    {
			//        TaxpayerId = docList.First().TaxpayerInfo.TaxpayerId,
			//        TaxpayerObjId = docList.First().TaxpayerInfo.TaxpayerObjId,
			//        TaxOrganId = docList.First().TaxpayerInfo.TaxOrganId,
			//        Type = docList.First().TaxpayerInfo.Type
			//    });

			//    foreach (RequirementDocDebt debt in docList)
			//    {
			//        debt.TaxpayerInfo = taxpayerInfo;

			//        // Заполняем КПП обособленного подразделения
			//        // (только для ЕТУ, если не совпадает с КПП самого ТУ)
			//        if (reqDoc.IsConsolidated && taxpayerInfo.Kpp != reqDoc.TaxpayerInfo.Kpp)
			//            debt.KppBranch = taxpayerInfo.Kpp;
			//    }
			//}

			//foreach (RequirementDocDebt debt in result)
			//{
			//    debt.Tax = BusinessFacadeForThesaurus.GetTaxById
			//        (new ThesRecordPicker(debt.Tax.RecordId, reqDoc.DocDate));
			//    debt.Okato = BusinessFacadeForThesaurus.GetOkatoById
			//        (new ThesRecordPicker(debt.Okato.RecordId, reqDoc.DocDate));
			//    debt.ReqTaxOrganId = reqDoc.TaxpayerInfo.TaxOrganId;
			//}

			// Получаем данные о текущем остатке непогашенной недоимки
			FillLastUnpdaidAmount(result);

			return result;
		}
		/// <summary>
		/// Заполняет поле "Текущий остаток непогашенной недоимки"
		/// </summary>
		/// <param name="reqDebtList">Недоимки Требования об уплате</param>
		private void FillLastUnpdaidAmount(IList<RequirementDocDebt> reqDebtList)
		{
			// Для строк с динамической автопеней проводим анализ -
			// если сумма погашена, отображаем текущее значение,
			// если сумма увеличилась - показываем сумму на момент формирования ТУ
			foreach (RequirementDocDebt reqDebt in reqDebtList)
			{
				if (reqDebt.PenyaType == PenyaType.ProstAv && reqDebt.LastUnpaidAmount > reqDebt.DebtUnpaidAmount)
					reqDebt.LastUnpaidAmount = reqDebt.DebtUnpaidAmount;
			}
		}
		/// <summary>
		/// Заполняет основные данные Недоимки ТУ (запрос данных НП не производится)
		/// </summary>
		/// <param name="reader">DAL-ридер</param>
		/// <returns></returns>
		private RequirementDocDebt GetDebtHeader(OracleDataReader reader)
		{
			RequirementDocDebt debt = new RequirementDocDebt();
			debt.Id = Convert.ToInt64(reader["id"]);
			debt.TaxpayerInfo.TaxOrganId = Convert.ToInt32(reader["tax_organ_id"]);
			debt.RequirementDocId = Convert.ToInt64(reader["req_id"]);
			debt.PersonalAccountDebtId = Convert.ToInt64(reader["pa_debt_id"]); ;
			debt.BufArrearId = Convert.ToInt64(reader["buf_arrear_id"]);
			debt.DebtUnpaidAmount = Convert.ToDecimal(reader["ballance_sum"]);
			debt.PersonalAccountId = Convert.ToInt64(reader["personal_account_id"]);
			debt.Tax.RecordId = Convert.ToInt32(reader["tax_id"]);
			debt.PaymentKind = (PaymentKind)Convert.ToInt32(reader["action_type_section_id"]);
			debt.Okato.RecordId = Convert.ToInt32(reader["okato_id"]);
			debt.TaxpayerStatus.Id = Convert.ToInt64(reader["tp_status_id"]);
			debt.TaxpayerStatus = null;//BusinessFacadeForThesaurus.GetTaxpayerStatusById(debt.TaxpayerStatus.Id);
			debt.ActionId = Convert.ToInt64(reader["action_id"]); ;
			debt.InitActionDate = Convert.ToDateTime(reader["init_action_date"]);
			debt.ActionType = Convert.ToInt32(reader["action_type"]);
			debt.InitSubsystemId = DBNullToObject<String>(reader["action_source_doc_creator"]);
			debt.InitCreatorDoc2Id = DBNullToObject<String>(reader["action_source_doc_guid"]);
			debt.InitDocTypeId = DBNullToValue<int>(reader["action_source_doc_kind"]);
			debt.InitDocNum = DBNullToObject<String>(reader["action_source_doc_num"]);
			debt.InitDocDate = DBNullToValue<DateTime>(reader["action_source_doc_date"]);
			debt.InitialAmount = Convert.ToDecimal(reader["initial_sum"]);
			debt.PeriodId = DBNullToValue<int>(reader["period_id"]);
			debt.FiscalYear = DBNullToValue<int>(reader["fiscal_year"]);
			debt.InitTransactionDate = DBNullToValue<DateTime>(reader["init_transaction_date"]);
			debt.LastTransactionDate = DBNullToValue<DateTime>(reader["transaction_date"]);
			debt.LastTransactionOrder = DBNullToValue<int>(reader["transaction_order"]);
			debt.PenyaType = (PenyaType?)DBNullToValue<int>(reader["penya_type"]);

			debt.TaxpayerInfo.TaxpayerId = Convert.ToString(reader["tp_id"]);
			if (reader["tp_obj_id"] != DBNull.Value)
				debt.TaxpayerInfo.TaxpayerObjId = Convert.ToString(reader["tp_obj_id"]);
			debt.TaxpayerInfo.Type = (TaxpayerTypeEnum.TaxpayerType)Convert.ToInt32(reader["type_np"]);
			debt.PaymentTerm = Convert.ToDateTime(reader["payment_term"]);
			debt.PdDocId = DBNullToValue<long>(reader["pd_id"]);
			debt.AvtoPenyaDebtSum = DBNullToValue<decimal>(reader["avtopenya_debt_sum"]);
			debt.LastUnpaidAmount = Convert.ToDecimal(reader["last_unpaid_amount"]);
			debt.InterestType = (InterestType?)DBNullToValue<int>(reader["percent_type"]);
			debt.TransferDcnType = (TransferDecisionType?)DBNullToValue<int>(reader["transfer_dcn_type"]);

			return debt;
		}
		private RequirementDoc GetDocHeader(OracleDataReader reader)
		{
			RequirementDoc header = new RequirementDoc();

			header.Id = Convert.ToInt64(reader["id"]);
			header.TaxpayerInfo.TaxOrganId = Convert.ToInt32(reader["tax_organ_id"]);
			header.TaxpayerInfo.TaxpayerId = Convert.ToString(reader["tp_id"]);
			if (reader["tp_obj_id"] != DBNull.Value)
				header.TaxpayerInfo.TaxpayerObjId = Convert.ToString(reader["tp_obj_id"]);
			header.TaxpayerInfo.Inn = DBNullToObject<String>(reader["inn"]);
			header.TaxpayerInfo.Kpp = DBNullToObject<String>(reader["kpp"]);
			header.TaxpayerInfo.Name = DBNullToObject<String>(reader["name"]);
			header.TaxpayerInfo.FirstName = DBNullToObject<String>(reader["f_name"]);
			header.TaxpayerInfo.SecondName = DBNullToObject<String>(reader["s_name"]);
			header.TaxpayerInfo.Adres = DBNullToObject<String>(reader["adres"]);
			header.TaxpayerInfo.OkvedCode = DBNullToObject<String>(reader["okved"]);
			header.TaxpayerInfo.Type = (TaxpayerTypeEnum.TaxpayerType)Convert.ToInt32(reader["type_np"]);
			header.TaxpayerDbsType = (TaxpayerTypeDbs)Convert.ToInt32(reader["type_np_dbs"]);
			header.DocNum = Convert.ToString(reader["doc_num"]);
			header.DocDate = Convert.ToDateTime(reader["doc_date"]);
			header.DocSum = Convert.ToDecimal(reader["doc_sum"]);
			header.PerformanceDate = Convert.ToDateTime(reader["performance_date"]);
			header.DocCreatorId = DBNullToValue<long>(reader["doc_creator_id"]);
			header.DocSignerId = DBNullToValue<long>(reader["doc_signer_id"]);
			header.DeliveryInfo = FillDeliveryInfo(reader);
			header.DocType = (ProcessType)Convert.ToInt32(reader["doc_type"]);
			header.TaxpayerDebtSumAll = Convert.ToDecimal(reader["debt_sum_all"]);
			header.TaxpayerDebtSumTax = Convert.ToDecimal(reader["debt_sum_tax"]);
			header.ResponseSign = (ResponseSignType)Convert.ToInt32(reader["response_sign"]);
			header.SpecifyingReqId = DBNullToValue<long>(reader["specifying_req_id"]);
			header.ReasonForTax = DBNullToObject<String>(reader["reason_for_tax"]);
			header.SpecifyingSign = (SpecifyingSignType)Convert.ToInt32(reader["specifying_req_sign"]);
			header.SuspensionSign = (SuspensionSignType)Convert.ToInt32(reader["suspension_sign"]);
			header.SuspensionDate = DBNullToValue<DateTime>(reader["suspension_date"]);
			header.SuspensionBaseDocType = (SuspensionBaseType?)DBNullToValue<int>(reader["suspension_base_doc_type"]);
			header.SuspensionBaseDocNum = DBNullToObject<String>(reader["suspension_base_doc_num"]);
			header.SuspensionBaseDocDate = DBNullToValue<DateTime>(reader["suspension_base_doc_date"]);
			header.ResumptionDate = DBNullToValue<DateTime>(reader["resumption_date"]);
			header.DocProcessingState = (DocProcessingStateType)(short)reader["doc_processing_state"];
			header.ApprovingInfo = FillApprovingInfo(reader);
			header.SigningInfo = FillSigningInfo(reader);
			header.UserComment = DBNullToObject<String>(reader["user_description"]);

			header.IsConsolidated = (Convert.ToInt32(reader["is_consolidated"]) == 1);
			header.IsReadyForWithdrawal = (Convert.ToInt32(reader["is_wdrw_ready"]) == 1);

			return header;
		}
		/// <summary>
		/// Получает данные о вручении из стандартных полей
		/// </summary>
		/// <param name="dataReader">Ридер БД</param>
		/// <returns></returns>
		protected DocDeliveryInfo FillDeliveryInfo(OracleDataReader dataReader)
		{
			DocDeliveryInfo result = new DocDeliveryInfo();

			result.DeliverySign = (DeliverySignType)(DBNullToValue<short>(dataReader["delivery_sign"]) ?? 0);
			result.DeliveryDate = DBNullToValue<DateTime>(dataReader["delivery_date"]);
			result.DeliveryWay = (DeliveryWayType?)DBNullToValue<int>(dataReader["delivery_way"]);
			result.DeliveryFlFio = DBNullToObject<String>(dataReader["delivery_fl_fio"]);
			result.LetterNum = DBNullToObject<String>(dataReader["letter_num"]);
			result.LetterSendDate = DBNullToValue<DateTime>(dataReader["letter_sending_date"]);

			return result;
		}
	}
}
